package com.jack.collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created by zhang_j on 2019/11/28
 * Iterator的安全失败是基于对底层集合做拷贝，因此，它不受源集合上修改的影响。
 *      java.util包下面的所有的集合类都是快速失败的，而java.util.concurrent包下面的所有类都是安全失败的。
 *      快速失败的迭代器会抛出ConcurrentModificationException异常，而安全失败的迭代器永远不会抛出这样的异常。
 *
 * fast-fail事件产生的条件：当多个线程对Collection进行操作时，若其中某一个线程通过iterator去遍历集合时，该集合的内容被其他线程所改变；则会抛出ConcurrentModificationException异常。
 * fast-fail解决办法：通过util.concurrent集合包下的相应类去处理，则不会产生fast-fail事件。
 *
 * 例如ArrayList就可以使用CopyOnWriteArrayList
 */
public class FastfailAndSafefail {
//    private static List<String> list = new ArrayList<>();
    private static List<String> list = new CopyOnWriteArrayList<>();
    public static void main(String[] args) {

        // 同时启动两个线程对list进行操作！
        ThreadOne();

        for (String s : list) {
            if("1".equals(s)){
                list.remove(s);
            }
        }
        printAll();
        //下面会出错，原因：forEach中定义了一个expectedModCount，开始与modCount相等
                //在forEach内部逻辑中，由于list执行remove操作使得modCount发生变化，而expectedModCount不变
        list.forEach(l->{
            if("2".equals(l)){
                list.remove(l);
            }
        });
    }

    private static void printAll() {
        System.out.println();

        String value ;
        Iterator iter = list.iterator();
        while(iter.hasNext()) {
            value = (String)iter.next();
            System.out.print(value+", ");
        }
    }

    /**
     * 向list中依次添加0,1,2,3,4,5，每添加一个数之后，就通过printAll()遍历整个list
     */
    private static void ThreadOne() {
        int i = 0;
        while (i<6) {
            list.add(String.valueOf(i));
            printAll();
            i++;
        }
    }

    /**
     * 向list中依次添加10,11,12,13,14,15，每添加一个数之后，就通过printAll()遍历整个list
     */
    private static class ThreadTwo extends Thread {
        @Override
        public void run() {
            int i = 10;
            while (i<16) {
                list.add(String.valueOf(i));
                printAll();
                i++;
            }
        }
    }
}
